﻿using System;

namespace MetaSharp.Transformation
{
    public sealed class ImmutableStack<T>
	{
		private ImmutableStack<T> parent;
		private StackItem item;

		public ImmutableStack()
			: this(null, new StackItem { count = 0 })
		{ }

		private ImmutableStack(ImmutableStack<T> parent, StackItem item)
		{
			this.parent = parent;
			this.item = item;
		}

		public int Count { get { return this.item.count; } }

		public T Peek()
		{
			return this.item.value;
		}

		public ImmutableStack<T> Push(T value)
		{
			var item = new StackItem
			{
				previous = this.item,
				count = this.item.count + 1,
				value = value
			};

			return new ImmutableStack<T>(this, item);
		}

		public ImmutableStack<T> Pop()
		{
			T value = default(T);
			return Pop(out value);
		}

		public ImmutableStack<T> Pop(out T value)
		{
			if (this.item.count == 0)
				throw new InvalidOperationException("Cannot pop an empty stack.");

			value = this.item.value;
			return new ImmutableStack<T>(this, this.item.previous);
		}

		private class StackItem
		{
			public T value;
			public StackItem previous;
			public int count;
		}
	}
}
